//MMU

#include "mmu.h"
#include "kmem.h"
#include "serial.h"
#include "mmu_asm.h"









void init_mmu() {
	//reserviere Speicher für L1 Cache
		    l1_address = (long*)(KERN_END + ((1<<14) - (KERN_END % (1<<14))));
	    kprintf("l1_address = %x\n",l1_address);
	    if(!((long)l1_address % (1 << 14))){
		    kprintf("16k-ausgerichtet!\n");
	    }
	    else{
		    kprintf("L1-Speicher falsch reserviert (%x), breche ab!\n",l1_address);
		    return;
	    }
	    int i;

	    i = 0;
	    long one_MB = 1 << 20;
	    for(i = 0; i < 4096; i++){
		    //initialisiere Einträge mit Section und einer Section Base Address
		    l1_address[i] = one_MB * i;
		    //AP-Bits auf 11 setzen
		    l1_address[i] += 0xC00;
		    //kprintf("l1_address[%d] = %x\n",i, l1_address[i]);
	    }
	    
	    //internen Speicherzugriff aktivieren, 0x0 - 0x0FFFFFFF
	    kprintf("internen Speicherzugriff aktivieren, 0x0 - 0x0FFFFFFF\n");
	    set_section_status((unsigned long*)0x0,2,256);
	    //externes RAM freigeben, 0x20000000 - 0x2FFFFFFF
	    kprintf("externes RAM freigeben, 0x20000000 - 0x2FFFFFFF\n");
	    set_section_status((unsigned long*)0x20000000,2,256);
	    //Konfliktadresse freigeben
	    kprintf("Konfliktadresse freigeben, 0xB0000000\n");
	    set_section_status((unsigned long*)0xB0000000,2,1);
	    //IO-Geräte freigeben, 0xF0000000 - 0xFFFFFFFF
	    kprintf("IO-Geräte freigeben, 0xF0000000 - 0xFFFFFFFF\n");
	    set_section_status((unsigned long*)0xF0000000,2,256);
	    
	    //Domäne 0 auf vollen Zugriff setzen
	    unsigned long domain_register = set_domain_rights_0(3);
	    kprintf("Domänenregister: %x\n",domain_register);
	    //registriere L1 Cache im Koprozessor 15
	    kprintf("Setze L1 Basisadresse\n");
	    unsigned long l1_address_test = set_L1_address(l1_address);
	    kprintf("eingetrage L1 Adresse: %x\n",l1_address_test);
	    kprintf("Aktiviere MMU\n");
	    enable_MMU();
	    kprintf("MMU aktiviert!\n");
}


//Alle Blöcke werden hintereinandergemappt
void map_memory(unsigned long *physicalAddress, unsigned long *virtualAddress, long number_of_1mb_blocks){
	  
	  long one_MB = 1 << 20;
	  long memory_block_nr = (unsigned long)virtualAddress/(long)(1<<20);
	  long masked_physical_address = (long)physicalAddress & (~(one_MB-1));
	  
	  int i;
	  
	  for(i = 0; i < number_of_1mb_blocks; i++){
	      //lösche Section-Base-Bits
	      l1_address[memory_block_nr+i] = l1_address[memory_block_nr+i] & (one_MB-1);
	      //setze neue Section-Base-Bits
	      l1_address[memory_block_nr+i] = l1_address[memory_block_nr+i] | (masked_physical_address + i*one_MB);
	  }
}
	
void set_section_status(unsigned long *virtualAddress, int status, long number_of_1mb_blocks){
	   long memory_block_nr = (unsigned long)virtualAddress/(long)(1<<20);
	   kprintf("memory_block_nr: %d\n",memory_block_nr);
	   int i;
	   for(i=0; i < number_of_1mb_blocks; i++){
		//lösche Statusbits
		 //kprintf("Setzte Status von l1_address[%d] von %x auf",memory_block_nr+i,l1_address[memory_block_nr+i]);
		  l1_address[memory_block_nr+i] = l1_address[memory_block_nr+i] & ~((1<<2)-1);
		  //setze neuen Status
		  l1_address[memory_block_nr+i] += status;
		  //kprintf(" %x (number of blocks: %d, i: %d)\n",l1_address[memory_block_nr+i],number_of_1mb_blocks,i);
	   }
}
 
  


